﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;

// last rev. 30 11 2010

namespace VkontakteMP3Downloader
{
    public partial class MainForm : Form
    {
        class MP3Song
        {
            public string URL { get; set; }
            public string Artist { get; set; }
            public string Title { get; set; }

            public string GetFileName
            {
                get
                {
                    return string.Format("{0} - {1}", Artist, Title);
                }
            }
        }

        Queue<MP3Song> SongsList = new Queue<MP3Song>();

        WebClient wClient = new WebClient();

        string SavePathFolder = @"C:\";

        public string GSid = string.Empty;

        public MainForm()
        {
            InitializeComponent();
            wClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wClient_DownloadProgressChanged);
            wClient.DownloadFileCompleted += new AsyncCompletedEventHandler(wClient_DownloadFileCompleted);
        }

        private string OpenAudioList()
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                using (StreamReader file = new StreamReader(openFileDialog1.FileName, Encoding.GetEncoding(1251), true))
                {
                    return file.ReadToEnd();
                }
            }
            else
            {
                return "";
            }
        }

        private void btDownload_Click(object sender, EventArgs e)
        {
            SongsList.Clear();
            foreach (var checkedItem in chklstSongsList.CheckedItems)
            {
                SongsList.Enqueue((MP3Song)checkedItem);
            }
            if (SongsList.FirstOrDefault() != null)
            {
                MP3Song tmp = SongsList.Dequeue();
                download(tmp.URL, SavePathFolder, tmp.GetFileName);
            }
            chklstSongsList.SelectionMode = SelectionMode.None;
        }

        private void download(string mp3url, string savepath, string fileName)
        {
            Uri url = new Uri(mp3url);
            savepath = string.Format(@"{0}\{1}.mp3", savepath, fileName);
            wClient.DownloadFileAsync(url, savepath);
            lbCurrentDownloading.Text = string.Format("Текущая песня: {0}", fileName);
            int index = chklstSongsList.FindString(fileName);
            chklstSongsList.SetItemChecked(index, false);
        }

        private void wClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            lbBytesProgress.Text = string.Format("Загружено {0} кб из {1} кб", e.BytesReceived / 1024, e.TotalBytesToReceive / 1024);
        }

        private void wClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            progressBar1.Value = 0;
            if (SongsList.FirstOrDefault() != null)
            {
                MP3Song tmp = SongsList.Dequeue();
                download(tmp.URL, SavePathFolder, tmp.GetFileName);
            }
            else
            {
                lbCurrentDownloading.Text = "Загрузка завершена";
                lbBytesProgress.Text = "";
                chklstSongsList.SelectionMode = SelectionMode.One;
            }
        }

        private void btSavePath_Click(object sender, EventArgs e)
        {
            ChangeFolder();
        }

        private void btCacelCurrent_Click(object sender, EventArgs e)
        {
            wClient.CancelAsync();
            lbCurrentDownloading.Text = "Отмена загрузки...";
            lbBytesProgress.Text = "";
        }

        private void btCancelAll_Click(object sender, EventArgs e)
        {
            wClient.CancelAsync();
            SongsList.Clear();
            foreach(int x in chklstSongsList.CheckedIndices)
            {
                chklstSongsList.SetItemCheckState(x, CheckState.Unchecked);
            }            
            lbCurrentDownloading.Text = "Загрузка отменена";
            lbBytesProgress.Text = "";
            chklstSongsList.SelectionMode = SelectionMode.One;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            rbAuth.Checked = true;
            tbSavePath.Text = SavePathFolder;
        }

        private void rbAuth_CheckedChanged(object sender, EventArgs e)
        {
            tbEmail.Enabled = true;
            tbPassword.Enabled = true;
            btLogIn.Enabled = true;
            btLogOut.Enabled = true;
        }

        private void rbSavedFile_CheckedChanged(object sender, EventArgs e)
        {
            if (rbAuth.Checked == false)
            {
                tbEmail.Enabled = false;
                tbPassword.Enabled = false;
                btLogIn.Enabled = false;
                btLogOut.Enabled = false;

                string songList = OpenAudioList();
                GetSongs(songList);
            }
        }

        private void tbSavePath_MouseClick(object sender, MouseEventArgs e)
        {
            ChangeFolder();
        }

        private void ChangeFolder()
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                SavePathFolder = folderBrowserDialog1.SelectedPath;
            }
            tbSavePath.Text = SavePathFolder;
        }

        protected void LoggedControlsOnOff(bool value) // if (value == true) — logged in site
        {
            tbEmail.Enabled = !value;
            tbPassword.Enabled = !value;
            btLogIn.Enabled = !value;
            lbIdList.Enabled = value;
            tbAudioListID.Enabled = value;
            btGetListbyID.Enabled = value;
            btReturnOwnList.Enabled = value;
            lbTotalSongs.Enabled = value;
            lbCurrentPage.Enabled = value;
            cbCurrentPage.Enabled = value;
            btChangePage.Enabled = value;
        }

        private void btLogIn_Click(object sender, EventArgs e)
        {
            if (tbEmail.Text == "" || tbPassword.Text == "")
            {
                MessageBox.Show("Заполните поля логина и пароля!");
            }
            else
            {
                bool auth = Authorization(tbEmail.Text, tbPassword.Text);
                if (auth == true)
                {
                    string MySongsList = DownloadMusicList(-1, "");
                    GetSongs(MySongsList);
                    LoggedControlsOnOff(true);
                }
                else
                {
                    MessageBox.Show("Ошибка авторизации. Проверьте правильность логина и пароля.");
                }
            }

        }

        public bool Authorization(string email, string password)
        {
            HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(@"http://vkontakte.ru/login.php");
            //WebReq.Proxy = new WebProxy("127.0.0.1", 8888);
            WebReq.Method = "POST";
            WebReq.AllowAutoRedirect = false;
            WebReq.ContentType = "application/x-www-form-urlencoded";
            byte[] sentData = Encoding.GetEncoding(1251).GetBytes("email=" + email + "&pass=" + password);
            WebReq.ContentLength = sentData.Length;
            Stream sendStream = WebReq.GetRequestStream();
            sendStream.Write(sentData, 0, sentData.Length);
            sendStream.Close();
            System.Net.WebResponse result = WebReq.GetResponse();
            string sCookies = "";
            if (!String.IsNullOrEmpty(result.Headers["Set-Cookie"]))
            {
                sCookies = result.Headers["Set-Cookie"];
            }
            var lines = sCookies.Split(';', ',');
            var sid = String.Empty;
            foreach (var l in lines)
                if (l.Contains("remixsid="))
                    sid = l.Remove(0, "remixsid=".Length);
            if (sid != "")
            {
                GSid = sid;
                return true;
            }
            else
            {
                return false;
            }
        }

        private string DownloadMusicList(int page, string audioListId)
        {
            string requestURL = string.Empty;

            if (audioListId == "")
            {
                requestURL = @"http://vkontakte.ru/audio.php";
            }
            else
            {
                requestURL = string.Format(@"http://vkontakte.ru/audio.php?id={0}", audioListId);
            }

            string pagePart = string.Empty;
            if (page > 0)
            {
                pagePart = string.Format("?gid=0&album_id=0&offset={0}", page * 100);                
            }
            requestURL += pagePart;

            WebRequest reqGET = WebRequest.Create(requestURL);

            reqGET.ContentType = "application/x-www-form-urlencoded";
            reqGET.Headers["Cookie"] = "remixlang=0; remixchk=5; remixsid=" + GSid;
            WebResponse resp = reqGET.GetResponse();
            Stream stream = resp.GetResponseStream();
            StreamReader sr = new StreamReader(stream, Encoding.GetEncoding(1251), true);
            string s = sr.ReadToEnd();

            if (cbCurrentPage.Items.Count == 0 || page < 0)
            {
                cbCurrentPage.Items.Clear();
                string totalSongsPattern = @"(?<=ary""><div>)[0-9]*";
                Regex rgxTotalSongs = new Regex(totalSongsPattern);
                Match totalSongs = rgxTotalSongs.Match(s);
                lbTotalSongs.Text = string.Format("Всего песен: {0}", totalSongs.Value);
                int songsCount = int.Parse(totalSongs.Value);
                int i = 1;
                while (songsCount > 0)
                {
                    songsCount -= 100;
                    cbCurrentPage.Items.Add(i++);
                }
                if (cbCurrentPage.SelectedIndex < 0)
                {
                    cbCurrentPage.SelectedIndex = 0;
                }
            }

            return s;
        }

        private void LogOut()
        {
            WebRequest reqGET = WebRequest.Create(@"http://vkontakte.ru/profile.php");
            reqGET.ContentType = "application/x-www-form-urlencoded";
            reqGET.Headers["Cookie"] = "remixlang=0; remixchk=5; remixsid=" + GSid;
            WebResponse resp = reqGET.GetResponse();
            Stream stream = resp.GetResponseStream();
            StreamReader sr = new StreamReader(stream, Encoding.GetEncoding(1251), true);
            string s = sr.ReadToEnd();
            string logOutLinkPatter = @"http://login.vk.com/\?act=logout&vk=&hash=[a-zA-Z0-9]*";
            Regex rgxLogOutLink = new Regex(logOutLinkPatter, RegexOptions.IgnoreCase);
            Match logOutLink = rgxLogOutLink.Match(s);
            reqGET = WebRequest.Create(logOutLink.Value);
            resp = reqGET.GetResponse();
        }

        private void GetSongs(string input)
        {
            SongsList.Clear();
            chklstSongsList.DisplayMember = "GetFileName";
            chklstSongsList.ValueMember = "URL";

            string urls = @"http://.*.mp3";
            string artists = @"(?<=q]=.*(""|')>).*(?=</a></b><span>)";     //@"(?<='>).*(?=</a></b>)";
            string titles = @"(?((showLyrics)+)((?<=;"">).*(?=</a>))|((?<=id=""title[0-9]*_[0-9]*"">).*(?=</span>)))"; //@"(?<=id=""title[0-9]*_[0-9]*"">).*(?=</span>)"; // @"(?<=id=""title[0-9]*\"">).*(?=</span>)";

            Regex rgxURLs = new Regex(urls, RegexOptions.IgnoreCase);
            Regex rgxArtists = new Regex(artists, RegexOptions.IgnoreCase);
            Regex rgxTitles = new Regex(titles, RegexOptions.IgnoreCase);

            MatchCollection urlMatches = rgxURLs.Matches(input);
            MatchCollection artistsMatches = rgxArtists.Matches(input);
            MatchCollection titlesMatches = rgxTitles.Matches(input);
            chklstSongsList.Items.Clear();
            for (int i = 0; i < urlMatches.Count; i++)
            {
                MP3Song tmpSong;
                if (titlesMatches[i].Value[0] == '<')
                {
                    string tempTitle = (new Regex(@"(?<=;"">).*(?=</a>)", RegexOptions.IgnoreCase)).
                        Match(titlesMatches[i].Value).Value;
                    tmpSong = new MP3Song()
                    {
                        URL = urlMatches[i].Value,
                        Artist = artistsMatches[i].Value,
                        Title = tempTitle
                    };
                }
                else
                {
                    tmpSong = new MP3Song()
                    {
                        URL = urlMatches[i].Value,
                        Artist = artistsMatches[i].Value,
                        Title = titlesMatches[i].Value
                    };
                }
                chklstSongsList.Items.Add(tmpSong);
            }
        }

        private void btLogOut_Click(object sender, EventArgs e)
        {
            LogOut();
            LoggedControlsOnOff(false);
        }

        private void btRefresh_Click(object sender, EventArgs e)
        {
            if (rbAuth.Checked == true)
            {
                string songList = DownloadMusicList(int.Parse(cbCurrentPage.SelectedText), tbAudioListID.Text);
                GetSongs(songList);
            }
        }

        private void btReturnOwnList_Click(object sender, EventArgs e)
        {
            tbAudioListID.Text = "";
            DownloadMusicList(-1, "");
        }

        private void btGetListbyID_Click(object sender, EventArgs e)
        {
            string songList = DownloadMusicList(-1, tbAudioListID.Text);
            GetSongs(songList);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string songList = DownloadMusicList(cbCurrentPage.SelectedIndex, tbAudioListID.Text);
            GetSongs(songList);
        }
    }
}
